const fs = require('fs')
const path = require('path')
const shell = require('shelljs')
const moment = require('moment')
const QRCode = require('qrcode')

const aliOss = require('./ali-oss')
const pgyer = require('./pgyer')
const { deployParam } = require('../models/api')

const execAsync = async (command) => {
  return new Promise((resolve, reject) => {
    shell.exec(command, (code, stdout, stderr) => {
      resolve({
        ret: code
        // stdout,
        // stderr
      })
    })
  })
}

// 安卓上传逻辑
const uploadAS = async (directory, key, env, suffix, branch = "master") => {
  let result
  let filename
  let basename
  try {
    filename = shell.exec(`ls ${directory}*.${suffix}`).stdout.trim()
  } catch (err) {}
  if (!filename) {
    return null
  }
  basename = path.basename(filename)
  result = await aliOss.uploadInner(`${key}/${env}/${branch}/${basename}`, filename)
  if (result instanceof Error) {
    return null
  }
  return result
}

const updateIOS = async (directory, env) => {
  let result
  let filename
  try {
    filename = shell.exec(`ls ${directory}*.ipa`).stdout.trim()
  } catch (err) {}
  if (!filename) {
    return null
  }
  result = await pgyer.update(filename, env)
  if (result instanceof Error) {
    return null
  }
  return result
}

const generateQR = async (text) => {
  let result
  try {
    result = await QRCode.toDataURL(text)
  } catch (err) {
    console.error(err)
  }
  return result
}

const wrapAppfileDataForAS = async (ret) => {
  let name = ret.name
  let suffix = path.extname(name).substr(1)
  let signatrueUrl = await aliOss.signatureUrlInner(name)
  let fetchUrl
  if (suffix === 'apk' || suffix === 'ipa') {
    fetchUrl = await generateQR(signatrueUrl)
  } else {
    fetchUrl = signatrueUrl
  }
  return {
    suffix,
    fetchUrl
  }
}

const wrapAppfileDataForIOS = async (ret) => {
  return {
    suffix: 'ipa',
    fetchUrl: ret.data.appQRCodeURL
  }
}

exports.execute = async (ctx, next) => {
  // 解析参数
  let key = ctx.params.key
  let body = ctx.request.body
  let deployConf = await deployParam(key)
  let command = deployConf.command
  let extraParams = 'noupload h5'
  if (body.Android === 'true') {
    extraParams = `${extraParams} android`
  }
  if (body.IOS === 'true') {
    extraParams = `${extraParams} ios`
  }
  let codeVersion = `${body.codeVersion[0]}.${body.codeVersion[1]}.${body.codeVersion[2]}`
  if (codeVersion === '0.0.0') {
    codeVersion = '0.0.1'
  }
  const gitBranchs = body.gitBranch.split('-')
  let gitBranch = gitBranchs[0] || "master"
  let secondGitBranch = gitBranchs[1] || "develop"

  console.log('==========================');
  const commandLine = `bash -x ${command} -C ${body.versionCode} -E ${body.nodeEnv} -S ${body.suffix} -U ${body.updatePolicy} -R ${body.releasePolicy} -N ${codeVersion} -G ${gitBranch} -L ${secondGitBranch} ${extraParams}`
  console.log(commandLine)
  let result = await execAsync(commandLine)
  console.info(result);
  console.log('==========================');

  // // 上传
  result.appfiles = {}
  if (result.ret !== 0) {
    ctx.response.status = 500
    return false
  }
  let nodeEnv = body.nodeEnv
  if (body.Android === 'true') {
    let apkFileRet, androidzipFileRet
    apkFileRet = await uploadAS(deployConf.androidAppPath, key, nodeEnv, 'apk', body.gitBranch)
    androidzipFileRet = await uploadAS(deployConf.androidAppPath, key, nodeEnv, 'zip', body.gitBranch)
    apkFileRet = Object.assign({}, apkFileRet, await wrapAppfileDataForAS(apkFileRet))
    androidzipFileRet = Object.assign({}, androidzipFileRet, await wrapAppfileDataForAS(androidzipFileRet))

    result.appfiles.android = []
    result.appfiles.android.push(apkFileRet, androidzipFileRet)
  }
  if (body.IOS === 'true') {
    let ipaFileRet
    ipaFileRet = await updateIOS(deployConf.iosAppPath, nodeEnv)
    ipaFileRet = Object.assign({}, ipaFileRet, await wrapAppfileDataForIOS(ipaFileRet))

    result.appfiles.ios = []
    result.appfiles.ios.push(ipaFileRet)
  }
  console.info(JSON.stringify(result));
  console.log('-------------------');

  ctx.body = result
}

exports.getList = async (ctx, next) => {
  let result = []
  let query = ctx.query
  let aliRet = await aliOss.listInner(query)
  if (!aliRet) {
    ctx.body = { ret: 1, data: result }
    return
  }
  let objects = aliRet.objects || []
  let tmp = objects.filter(item => {
    return path.extname(item.name) !== '.zip'
  })
  tmp.sort((a, b) => {
    return moment(b.lastModified) - moment(a.lastModified)
  })
  tmp.forEach(item => {
    result.push([item])
  })
  result.forEach(item => {
    let name = item[0].name
    let zip = objects.filter(obj => {
      return path.extname(obj.name) === '.zip' && obj.name.indexOf(name) !== -1
    })
    if (!zip.length) {
      return
    }
    item.push(...zip)
  })
  for (let i = 0, j = result.length; i < j; i++) {
    let _wrapData0 = await wrapAppfileDataForAS(result[i][0])
    let lastModifiedFormat0 = moment(result[i][0].lastModified).format('YYYY-MM-DD HH:mm:ss')
    result[i][0] = Object.assign({}, result[i][0], _wrapData0, { lastModifiedFormat: lastModifiedFormat0 })
    if (!result[i][0].name || result[i].length < 2) {
      continue
    }
    let _wrapData1 = await wrapAppfileDataForAS(result[i][1])
    let lastModifiedFormat1 = moment(result[i][1].lastModified).format('YYYY-MM-DD HH:mm:ss')
    result[i][1] = Object.assign({}, result[i][1], _wrapData1, { lastModifiedFormat: lastModifiedFormat1 })
  }
  ctx.body = {
    ret: 0,
    data: result
  }
}
